package org.Yiran.timetale_re.block.decorate.longtable;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.MapItem;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.network.PacketDistributor;
import org.Yiran.timetale_re.item.ItemsRegister;
import org.Yiran.timetale_re.item.rune.base.RuneItem;
import org.Yiran.timetale_re.item.runeblueprint.base.RuneBlueprintItem;
import org.Yiran.timetale_re.network.NetworkChannel;
import org.Yiran.timetale_re.network.SCResponsePacket;
import org.Yiran.timetale_re.tile.blocktile.LongTableBlockEntity;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 长桌物品处理器类
 * 处理在长桌上放置和取回物品的逻辑
 * <p>
 * 主要功能:
 * 1. 处理物品放置和取回
 * 2. 处理特殊物品交互（如混沌水晶与石碑）
 * 3. 管理物品的位置、旋转和偏移
 * 4. 处理网络同步和冷却机制
 */
public class LongTableItemHandler {
    
    // ==================== 常量和冷却机制 ====================
    
    /** 玩家操作冷却映射表，防止重复操作 */
    private static final Map<UUID, Long> playerOperationCooldown = new HashMap<>();
    
    /** 操作冷却时间（游戏刻） */
    private static final long OPERATION_COOLDOWN = 5; // 5 ticks cooldown

    // ==================== 主要交互处理方法 ====================

    /**
     * 处理物品交互逻辑
     * 根据玩家手持物品和长桌当前状态决定是放置物品、取回物品还是处理特殊交互
     * 
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     * @param player 玩家
     * @param hand 手部
     * @param hit 点击结果
     * @return 交互结果
     */
    public static InteractionResult handleItemInteraction(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
        if (level.isClientSide) {
            return InteractionResult.SUCCESS;
        }

        // 检查玩家操作冷却
        if (isPlayerOnCooldown(player, level)) {
            return InteractionResult.PASS;
        }

        // 获取长桌方块实体
        LongTableBlockEntity tableEntity = getLongTableBlockEntity(state, level, pos);
        if (tableEntity == null) {
            return InteractionResult.PASS;
        }

        // 获取交互相关信息
        Direction facing = state.getValue(LongTable.FACING);
        int partId = getPartId(pos, getMainPos(pos, state), facing);
        ItemStack currentItem = tableEntity.getItem(partId);
        ItemStack heldItem = player.getItemInHand(hand);

        // 处理混沌水晶与石碑的交互
        if (!heldItem.isEmpty() && !currentItem.isEmpty()) {
            InteractionResult chaosResult = handleChaosGemInteraction(state, level, pos, player, tableEntity,
                    partId, currentItem, heldItem);
            if (chaosResult != InteractionResult.PASS) {
                setPlayerCooldown(player, level);
                return chaosResult;
            }
        }

        // 根据不同情况处理物品交互
        if (!heldItem.isEmpty() && currentItem.isEmpty()) {
            return handleItemPlacement(state, level, pos, player, hand, hit, tableEntity, partId, heldItem, facing);
        } else if (heldItem.isEmpty() && !currentItem.isEmpty()) {
            return handleItemRetrieval(state, level, pos, player, tableEntity, partId, currentItem, hit);
        }

        return InteractionResult.SUCCESS;
    }

    // ==================== 冷却时间管理 ====================

    /**
     * 检查玩家是否在冷却时间内
     * 防止玩家过快地进行操作
     *
     * @param player 玩家
     * @param level 世界对象
     * @return 是否在冷却中
     */
    private static boolean isPlayerOnCooldown(Player player, Level level) {
        UUID playerId = player.getUUID();
        long currentTime = level.getGameTime();

        if (playerOperationCooldown.containsKey(playerId)) {
            long cooldownEnd = playerOperationCooldown.get(playerId);
            return currentTime < cooldownEnd;
        }
        return false;
    }

    /**
     * 设置玩家操作冷却
     * @param player 玩家
     * @param level 世界对象
     */
    private static void setPlayerCooldown(Player player, Level level) {
        playerOperationCooldown.put(player.getUUID(), level.getGameTime() + OPERATION_COOLDOWN);
    }

    // ==================== 特殊物品交互处理 ====================

    /**
     * 处理混沌水晶与石碑的交互
     * 当玩家手持混沌水晶右键点击石碑时，将石碑转换为空白符文
     * 
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     * @param player 玩家
     * @param tableEntity 长桌方块实体
     * @param partId 部件ID
     * @param currentItem 当前物品
     * @param heldItem 手持物品
     * @return 交互结果
     */
    private static InteractionResult handleChaosGemInteraction(BlockState state, Level level, BlockPos pos,
                                                               Player player, LongTableBlockEntity tableEntity,
                                                               int partId, ItemStack currentItem, ItemStack heldItem) {
        // 检查当前物品是否为石碑且手持物品是否为混沌水晶
        if (currentItem.getItem() == ItemsRegister.STONE_TABLET.get() &&
                heldItem.getItem() == ItemsRegister.CHAOS_GEM.get()) {

            // 消耗一个混沌水晶（创造模式不消耗）
            if (!player.isCreative()) {
                heldItem.shrink(1);
            }

            // 创建空白符文
            ItemStack blankRune = RuneItem.createBlankRune();

            // 计算物品的旋转和偏移
            float rotation = tableEntity.getItemRotation(partId);
            float xOffset = tableEntity.getItemXOffset(partId);
            float zOffset = tableEntity.getItemZOffset(partId);

            // 替换石碑为空白符文
            tableEntity.setItem(partId, blankRune, rotation, xOffset, zOffset);

            // 更新方块实体
            updateBlockEntity(level, state, getMainPos(pos, state), tableEntity);

            // 添加转换音效和粒子效果（可选）
            level.playSound(null, pos, net.minecraft.sounds.SoundEvents.ENCHANTMENT_TABLE_USE,
                    net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);

            return InteractionResult.CONSUME;
        }

        return InteractionResult.PASS;
    }

    // ==================== 方块实体获取 ====================

    /**
     * 获取长桌方块实体
     * 确保获取到的是主方块的实体，因为长桌由两个方块组成
     * 
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     * @return 长桌方块实体
     */
    private static LongTableBlockEntity getLongTableBlockEntity(BlockState state, Level level, BlockPos pos) {
        BlockPos mainPos = getMainPos(pos, state);
        BlockEntity blockEntity = level.getBlockEntity(mainPos);
        return blockEntity instanceof LongTableBlockEntity ? (LongTableBlockEntity) blockEntity : null;
    }

    // ==================== 物品放置处理 ====================

    /**
     * 处理物品放置逻辑
     * 当玩家手持物品右键点击空的长桌部分时调用
     * 
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     * @param player 玩家
     * @param hand 手部
     * @param hit 点击结果
     * @param tableEntity 长桌方块实体
     * @param partId 部件ID
     * @param heldItem 手持物品
     * @param facing 朝向
     * @return 交互结果
     */
    private static InteractionResult handleItemPlacement(BlockState state, Level level, BlockPos pos, Player player,
                                                         InteractionHand hand, BlockHitResult hit,
                                                         LongTableBlockEntity tableEntity, int partId,
                                                         ItemStack heldItem, Direction facing) {
        // 移除这行双重检查代码，因为它可能导致问题：
        // ItemStack currentItem = tableEntity.getItem(partId);
        // if (!currentItem.isEmpty()) {
        //     return InteractionResult.PASS; // 物品已存在，不能放置
        // }

        // 创建要放置的物品
        ItemStack itemToPlace = createItemToPlace(heldItem);

        // 计算物品旋转角度
        float rotation = calculateItemRotation(player);

        // 计算物品偏移位置
        Vec3 offset = calculateItemOffset(hit, pos, facing);
        float xOffset = (float) offset.x;
        float zOffset = (float) offset.y;

        // 放置物品
        if (tableEntity.setItem(partId, itemToPlace, rotation, xOffset, zOffset)) {
            if (!player.isCreative()) {
                heldItem.shrink(1);
            }

            // 设置操作冷却
            setPlayerCooldown(player, level);

            // 更新方块实体
            updateBlockEntity(level, state, getMainPos(pos, state), tableEntity);
            return InteractionResult.CONSUME;
        }

        return InteractionResult.PASS;
    }

    /**
     * 创建要放置的物品
     * 从手持物品创建一个副本，数量为1
     * 
     * @param heldItem 手持物品
     * @return 要放置的物品
     */
    private static ItemStack createItemToPlace(ItemStack heldItem) {
        ItemStack itemToPlace = heldItem.copy();
        itemToPlace.setCount(1);
        return itemToPlace;
    }

    /**
     * 计算物品旋转角度
     * 根据玩家朝向计算物品的初始旋转角度
     * 
     * @param player 玩家
     * @return 旋转角度
     */
    private static float calculateItemRotation(Player player) {
        float playerYaw = player.getYRot();
        float rotation = playerYaw % 360;
        if (rotation < 0) {
            rotation += 360;
        }
        return rotation;
    }

    /**
     * 计算物品偏移位置
     * 根据玩家点击位置计算物品相对于方块中心的偏移
     * 
     * @param hit 点击结果
     * @param pos 方块位置
     * @param facing 朝向
     * @return 偏移向量(X, Z)
     */
    private static Vec3 calculateItemOffset(BlockHitResult hit, BlockPos pos, Direction facing) {
        // 计算点击位置相对于方块中心的偏移
        Vec3 hitPos = hit.getLocation();
        double localX = hitPos.x - pos.getX();
        double localZ = hitPos.z - pos.getZ();

        // 转换为相对于方块中心的坐标 (-0.5 到 0.5)
        float xOffset = (float) (localX - 0.5);
        float zOffset = (float) (localZ - 0.5);

        // 根据方块朝向调整坐标系
        float adjustedXOffset = xOffset;
        float adjustedZOffset = zOffset;
        switch (facing) {
            case NORTH -> {
                adjustedXOffset = (float) -localZ + 0.5f;
                adjustedZOffset = (float) localX - 0.5f;
            }
            case SOUTH -> {
                adjustedXOffset = (float) localZ - 0.5f;
                adjustedZOffset = (float) -localX + 0.5f;
            }
            case WEST -> {
                adjustedXOffset = (float) localX - 0.5f;
                adjustedZOffset = (float) localZ - 0.5f;
            }
            case EAST -> {
                adjustedXOffset = (float) -localX + 0.5f;
                adjustedZOffset = (float) -localZ + 0.5f;
            }
        }

        return new Vec3(adjustedXOffset, adjustedZOffset, 0);
    }

    // ==================== 物品取回处理 ====================

    /**
     * 处理物品取回逻辑
     * 当玩家空手右键点击有物品的长桌部分时调用
     * 
     * @param state 方块状态
     * @param level 世界对象
     * @param pos 方块位置
     * @param player 玩家
     * @param tableEntity 长桌方块实体
     * @param partId 部件ID
     * @param currentItem 当前物品
     * @param hit 点击结果
     * @return 交互结果
     */
    private static InteractionResult handleItemRetrieval(BlockState state, Level level, BlockPos pos, Player player,
                                                         LongTableBlockEntity tableEntity, int partId,
                                                         ItemStack currentItem, BlockHitResult hit) {
        BlockPos mainPos = getMainPos(pos, state);
        Direction facing = state.getValue(LongTable.FACING);

        // 检查是否点击了物品渲染位置附近
        if (isHitNearItem(hit, pos, partId, facing, tableEntity, mainPos)) {
            // 移除双重检查代码
            // ItemStack checkItem = tableEntity.getItem(partId);
            // if (checkItem.isEmpty()) {
            //     return InteractionResult.PASS; // 物品已不存在，不能取回
            // }

            // 取回物品
            ItemStack removedItem = tableEntity.removeItem(partId);
            if (!removedItem.isEmpty()) {
                player.getInventory().placeItemBackInInventory(removedItem);

                // 设置操作冷却
                setPlayerCooldown(player, level);

                // 更新方块实体
                updateBlockEntity(level, state, mainPos, tableEntity);
                return InteractionResult.CONSUME;
            }
        }

        return InteractionResult.PASS;
    }

    // ==================== 方块实体更新 ====================

    /**
     * 更新方块实体
     * 同步方块实体状态到客户端
     * 
     * @param level 世界对象
     * @param state 方块状态
     * @param pos 方块位置
     * @param tableEntity 长桌方块实体
     */
    private static void updateBlockEntity(Level level, BlockState state, BlockPos pos, LongTableBlockEntity tableEntity) {
        tableEntity.setChanged();
        // 使用更全面的更新标志确保客户端同步
        level.sendBlockUpdated(pos, state, state, Block.UPDATE_ALL);

        // 添加网络数据包同步确保客户端正确显示
        NetworkChannel.CHANNEL.send(
                PacketDistributor.TRACKING_CHUNK.with(() -> level.getChunkAt(pos)),
                new SCResponsePacket.LongTableItemSyncPacket(pos, 0, tableEntity.leftItem, tableEntity.leftItemRotation,
                        tableEntity.leftItemXOffset, tableEntity.leftItemZOffset)
        );
        NetworkChannel.CHANNEL.send(
                PacketDistributor.TRACKING_CHUNK.with(() -> level.getChunkAt(pos)),
                new SCResponsePacket.LongTableItemSyncPacket(pos, 1, tableEntity.rightItem, tableEntity.rightItemRotation,
                        tableEntity.rightItemXOffset, tableEntity.rightItemZOffset)
        );
    }

    // ==================== 位置和交互检测 ====================

    /**
     * 检查点击位置是否在物品渲染位置附近
     * 确保玩家点击的是物品本身而不是空旷区域
     * 
     * @param hit 点击结果
     * @param pos 方块位置
     * @param partId 部件ID
     * @param facing 朝向
     * @param tableEntity 长桌方块实体
     * @param mainPos 主方块位置
     * @return 是否在附近
     */
    private static boolean isHitNearItem(BlockHitResult hit, BlockPos pos, int partId, Direction facing, LongTableBlockEntity tableEntity, BlockPos mainPos) {
        ItemStack currentItem = tableEntity.getItem(partId);

        // 如果是地图物品或符文图纸，只需点击对应桌面部分即可
        if (currentItem.getItem() instanceof MapItem || currentItem.getItem() instanceof RuneBlueprintItem) {
            // 获取点击的方块位置
            BlockPos hitPos = hit.getBlockPos();
            // 检查点击位置是否为当前部分的桌面
            return hitPos.equals(pos);
        }

        // 其他物品保持原有逻辑
        // 获取点击位置
        Vec3 hitPos = hit.getLocation();

        // 计算物品渲染位置 - 使用mainPos来正确计算右半部分物品位置
        Vec3 itemRenderPos = LongTable.getItemRenderPosition(mainPos, partId, facing, tableEntity);

        // 计算点击位置与物品渲染位置的距离
        double distance = hitPos.distanceTo(itemRenderPos);

        // 如果距离小于0.3，则认为点击位置接近物品
        return distance < 0.3;
    }

    /**
     * 获取主方块位置（左半部分）
     * 确保总是获取到长桌的主方块位置
     * 
     * @param pos 当前位置
     * @param state 方块状态
     * @return 主方块位置
     */
    private static BlockPos getMainPos(BlockPos pos, BlockState state) {
        return LongTable.getMainPos(pos, state);
    }

    /**
     * 根据当前位置和主位置计算部件ID
     * 确定当前操作的是长桌的左半部分还是右半部分
     * 
     * @param pos 当前位置
     * @param mainPos 主位置
     * @param facing 朝向
     * @return 部件ID
     */
    private static int getPartId(BlockPos pos, BlockPos mainPos, Direction facing) {
        if (pos.equals(mainPos)) {
            return LongTable.LEFT_PART;
        } else {
            return LongTable.RIGHT_PART;
        }
    }
}